package pers.xiaojun.boot.security.filter;

import cn.hutool.core.util.StrUtil;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.web.filter.OncePerRequestFilter;
import pers.xiaojun.boot.common.biz.system.oauth2.OAuth2TokenCommonApi;
import pers.xiaojun.boot.common.biz.system.oauth2.dto.OAuth2AccessTokenRespDTO;
import pers.xiaojun.boot.security.config.properties.SecurityProperties;
import pers.xiaojun.boot.security.pojo.AuthUserDetails;
import pers.xiaojun.boot.security.util.SecurityUtils;

import java.io.IOException;

/**
 * Token拦截器
 *
 * @author xiaojun
 * @since 2025-10-08
 */
@RequiredArgsConstructor
public class TokenAuthenticationFilter extends OncePerRequestFilter {

    private final SecurityProperties securityProperties;
    private final OAuth2TokenCommonApi authTokenApi;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String token = extractTokenAuthorization(request);
        if (StrUtil.isNotEmpty(token)) {
            AuthUserDetails userDetails;

            userDetails = buildAuthUserDetailsByToken(token);

            if (userDetails == null && securityProperties.isMock()) {
                userDetails = buildMockAuthUserDetails(token);
            }
            if (userDetails != null) {
                SecurityUtils.setAuthentication(userDetails, request);
            }
        }

        filterChain.doFilter(request, response);
    }

    /**
     * 在请求头中获得Token
     *
     * @return token
     */
    private String extractTokenAuthorization(HttpServletRequest request) {
        return SecurityUtils.extractTokenAuthorization(request, securityProperties.getTokenHeader(), securityProperties.getTokenPrefix());
    }

    /**
     * 根据Token获得认证用户信息
     *
     * @param token Token
     * @return 用户认证信息
     */
    private AuthUserDetails buildAuthUserDetailsByToken(String token) {
        OAuth2AccessTokenRespDTO accessToken = authTokenApi.checkAccessToken(token);
        if (accessToken == null) {
            return null;
        }
        return AuthUserDetails.builder()
                .id(accessToken.getUserId())
                .scopes(accessToken.getScopes())
                .tenantId(accessToken.getTenantId())
                .build();
    }

    /**
     * Mock模式下构建模拟用户
     *
     * @param token Token
     * @return 用户认证信息
     */
    private AuthUserDetails buildMockAuthUserDetails(String token) {
        if (token.startsWith(securityProperties.getMockTokenPrefix())) {
            String userIdStr = token.substring(securityProperties.getMockTokenPrefix().length());
            if (StrUtil.isEmpty(userIdStr)) {
                return null;
            }
            return AuthUserDetails.builder().id(Long.parseLong(userIdStr)).build();
        }
        return null;
    }

}
